/*
 *  proxy_reader.cpp
 *  proxy_hunter
 *
 *  Created by Roy Zuo on May 13, 2010.
 *  Copyright 2010 O2 Micro, Inc. All rights reserved.
 *
 */

#include "proxy_reader.hpp"

#include <iostream>
#include <boost/regex.hpp>

ProxyReader::ProxyReader ( const string& db_file )
: _connection ( 0 )
{
	open_database ( db_file );
}
ProxyReader::~ProxyReader ()
{
	close_database ();
}

void ProxyReader::open_database ( const string& db_file )
{
	if ( _connection )
	{
		close_database ();	
	}

	try
	{
		_connection = new sqlite3_connection ( db_file.c_str() );

		int count = _connection->executeint("select count(*) from sqlite_master where name='t_proxies';");
		if(count==0) _connection->executenonquery ( SQL_PROXIES_CREATE_TABLE );
	}
	catch ( exception &ex )
	{
		cerr << "Exception Occured: " << ex.what() << endl;
	}
}

void ProxyReader::close_database()
{
	if ( _connection )
	{
		_connection->close();
		delete _connection;
		_connection = 0;
	}
}

void ProxyReader::read_select_results( sqlite3_reader& reader, vector< string >& proxies )
{
	try
	{
		while(reader.read())
		{
			string proxy = reader.getstring( 0 );
			proxies.push_back ( proxy );
		}
	}
	catch ( exception& ex )
	{
		cerr << "Exception Occured: " << ex.what() << endl;
	}
}

void ProxyReader::Delete( int status )
{

}

void ProxyReader::Delete( const vector< string >& proxies )
{

}

void ProxyReader::Delete( const string& proxy )
{

}

void ProxyReader::DeleteAll()
{

}

void ProxyReader::Insert( const vector< string >& proxies, int status )
{
	for ( vector< string >::const_iterator iter = proxies.begin(); iter != proxies.end(); iter ++ )
	{
		Insert ( *iter, status );
	}
}

void ProxyReader::Insert( const string& proxy, int status )
{
	try
	{
		string sql(SQL_PROXIES_SELECT_COUNT);
		sql += " WHERE proxy=?;";

		sqlite3_command st ( *_connection, sql.c_str() );
		st.bind ( 1, proxy.c_str(), proxy.length() );
		int count = st.executeint();
		if ( count == 0 )
		{
			sqlite3_transaction trans ( *_connection );

			{
				sqlite3_command cmd  ( *_connection, SQL_PROXIES_INSERT );
				cmd.bind ( 1, proxy.c_str(), proxy.length() );
				cmd.bind ( 2, status );
				cmd.executenonquery();
			}

			trans.commit();

		}
	}
	catch ( exception& ex )
	{
		cerr << "Exception Occured: " << ex.what() << endl;
	}
}

void ProxyReader::SelectWithResponseTime( int response_time, vector< string >& proxies )
{
	try
	{
		string sql(SQL_PROXIES_SELECT);
		sql += " WHERE response_time<?;";

		sqlite3_command st ( *_connection, sql.c_str() );
		st.bind ( 1, response_time );
		sqlite3_reader reader = st.executereader();
		
		read_select_results ( reader, proxies );
	}
	catch ( exception& ex )
	{
		cerr << "Exception Occured: " << ex.what() << endl;
	}
}

void ProxyReader::SelectWithStatus ( int status, vector< string >& proxies )
{
	try
	{
		string sql(SQL_PROXIES_SELECT);
		sql += " WHERE status=?;";

		sqlite3_command st ( *_connection, sql.c_str() );
		st.bind ( 1, status );
		sqlite3_reader reader = st.executereader();

		read_select_results ( reader, proxies );
	}
	catch ( exception& ex )
	{
		cerr << "Exception Occured: " << ex.what() << endl;
	}
}

void ProxyReader::Update ( const vector< string >& proxies, int status, int response_time )
{
	for ( vector< string >::const_iterator iter = proxies.begin(); iter != proxies.end(); iter ++ )
	{
		Update ( *iter, status, response_time );
	}
}

void ProxyReader::Update( const string& proxy, int status, int response_time )
{
	try
	{
		string sql ( SQL_PROXIES_UPDATE );
		sql += " WHERE proxy=?;";

		sqlite3_transaction trans ( *_connection );

		{
			sqlite3_command cmd ( *_connection, sql.c_str() );

			cmd.bind ( 1, status );
			cmd.bind ( 2, response_time );
			cmd.bind ( 3, proxy.c_str(), proxy.length() );

			cmd.executenonquery();
		}

		trans.commit();
	}
	catch ( exception& ex )
	{
		cerr << "Exception Occured: " << ex.what() << endl;
	}
}

void ProxyReader::UpdateAll ( int status, int response_time )
{

}

void ProxyReader::SplitProxy ( const string& proxy, string& host, string& port )
{
	boost::regex expr1 ( "^(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}):(\\d+)$" );

	boost::cmatch what;
	if ( boost::regex_match ( proxy.c_str(), what, expr1 ) )
	{
		host = string ( what[1].first, what[1].second );
		port = string ( what[2].first, what[2].second );
	}
}

void ProxyReader::MergeProxy ( const string& host, const string& port, string& proxy )
{
	proxy = host + ":" + port;
}